#pragma once

#include<iostream>
#include<string>
#include<unistd.h>
#include<cstring>
#include<cstdlib>
#include<sys/types.h>
#include<sys/socket.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<sys/wait.h>
#include<pthread.h>
#include"Task.hpp"
#include"ThreadPool.hpp"



enum{
    UsageErr = 1,
    SocketErr,
    BindErr,
    ListenErr,
};


const uint16_t defaultport = 8888;
const std::string defaultip = "0.0.0.0";
const int backlog = 5;

class TcpServer;

// class ThreadData
// {
// public:
//     ThreadData(int sockfd,uint16_t port,std::string ip,TcpServer* tsrv)
//         :sockfd(sockfd)
//         ,port(port)
//         ,ip(ip)
//         ,tsrv(tsrv)
//     {}
// public:
//     int sockfd;
//     uint16_t port;
//     std::string ip;
//     TcpServer* tsrv;
// };

class TcpServer
{
public:
    TcpServer(uint16_t port = defaultport, std::string ip = defaultip)
        :_listensock(-1)
        ,_port(port)
        ,_ip(defaultip)
    {}

    void initServer()
    {
        //1.创建套接字
        _listensock = socket(AF_INET,SOCK_STREAM,0);
        if(_listensock < 0)
        {
            std::cerr << "create socket failed, errno: " << errno << " ,err string: " << strerror(errno) << std::endl;
            exit(SocketErr);
        }
        std::cout << "create socket success" << std::endl;

        // 防止偶发性的服务器无法进行立即重启(tcp协议的时候再说)
        int opt = 1;
        setsockopt(_listensock, SOL_SOCKET, SO_REUSEADDR|SO_REUSEPORT, &opt, sizeof(opt)); 

        //2.绑定
        struct sockaddr_in local;
        memset(&local,0,sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        inet_aton(_ip.c_str(),&(local.sin_addr));
        socklen_t len = sizeof(local);

        if(bind(_listensock,(struct sockaddr*)&local,len) < 0)
        {
            std::cerr << "bind failed, errno: " << errno << " ,err string: " << strerror(errno) << std::endl;
            exit(BindErr);
        }
        std::cout << "bind success" << std::endl;
        
        //3.监听
        if(listen(_listensock,backlog) < 0)
        {
            std::cerr << "listen failed, errno: " << errno << " ,err string: " << strerror(errno) << std::endl;
            exit(ListenErr);
        }
        std::cout << "listen success" << std::endl;

    }

    // static void* Routine(void* args)
    // {
    //     pthread_detach(pthread_self());
    //     ThreadData* td = static_cast<ThreadData*>(args);
    //     td->tsrv->Service(td->sockfd,td->port,td->ip);
    //     delete td;
    //     return nullptr;
    // }

    void start()
    {
        ThreadPool<Task>::GetInstance()->start();
        while(1)
        {
            //接受新链接
            struct sockaddr_in client;
            socklen_t len = sizeof(client);
            int sockfd = accept(_listensock,(struct sockaddr*)&client,&len);
            if(sockfd < 0)
            {
                std::cerr << "listen failed, errno: " << errno << " ,err string: " << strerror(errno) << std::endl;
                continue;
            }
            
            //获取客户端ip和port
            uint16_t clientport = ntohs(client.sin_port);
            char clientip[32];
            inet_ntop(AF_INET,&(client.sin_addr),clientip,sizeof(clientip));
            std::cout << "accpet a new link... sockfd: " << sockfd << std::endl;

            //v1 单进程版本
            // Service(sockfd,clientport,clientip);
            // close(sockfd);

            //v2 多进程版本
            // pid_t id = fork();
            // if(id == 0)
            // {
            //     close(_listensock);
            //     if(fork() > 0)
            //     {
            //         //孩子
            //         exit(0);
            //     }
            //     //孙子
            //     Service(sockfd,clientport,clientip);//系统领养
            //     close(sockfd);
            //     exit(0);
            // }
            // //父亲
            // close(sockfd);
            // pid_t rid = waitpid(id,nullptr,0);

            //v3 多线程版本
            // pthread_t pid;
            // ThreadData* td = new ThreadData(sockfd,clientport,clientip,this);
            // pthread_create(&pid,nullptr,Routine,td);

            //v4 线程池版本
            Task t(sockfd,clientport,clientip);
            ThreadPool<Task>::GetInstance()->push(t);

        }
    }

    // void Service(int sockfd, uint16_t clientport, std::string clientip)
    // {   
    //     char buffer[4096];
    //     while(1)
    //     {
    //         //接受消息
    //         ssize_t n = read(sockfd,buffer,sizeof(buffer));
    //         if(n > 0)
    //         {
    //             buffer[n] = 0;
    //             std::cout << "Clinet say# " << buffer << std::endl;

    //             std::string echo_string = "TcpServer echo# ";
    //             echo_string += buffer;

    //             //返回消息
    //             write(sockfd,echo_string.c_str(),echo_string.size());
    //         }
    //         else if(n == 0)
    //         {
    //             std::cout << "client shut down ,clientip:" << clientip << " ,clientport:" << clientport << std::endl;
    //             break; 
    //         }
    //         else
    //         {
    //             std::cout << "read failed" << std::endl;
    //             break;
    //         }
    //     }
    // }

    ~TcpServer()
    {}
private:
    int _listensock;
    uint16_t _port;
    std::string _ip;
};